package cn.iocoder.yudao.framework.business.address.dao;

import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.business.address.pojo.form.AddressQueryDTO;
import cn.iocoder.yudao.framework.business.address.pojo.po.AddressBaseDO;
import cn.iocoder.yudao.framework.business.basic.dao.mapper.CoreMapper;
import cn.iocoder.yudao.framework.business.basic.dao.query.CoreQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import jakarta.annotation.Nonnull;

/**
 * 地址 Mapper，由子类继承，子类标注 @{@link org.apache.ibatis.annotations.Mapper}
 *
 * @author 山野羡民
 */
public interface AddressMapper<DO extends AddressBaseDO, QUERY extends AddressQueryDTO> extends CoreMapper<DO> {

    @Nonnull
    default QueryWrapper<DO> buildQueryWrapper(QUERY reqVO) {
        CoreQueryWrapper<DO> wrapper = new CoreQueryWrapper<>();
        wrapKeyword(wrapper, reqVO.getKeyword());
        wrapRegionCode(wrapper, reqVO.getProvinceCode(), reqVO.getCityCode(), reqVO.getCountyCode());
        wrapLongitudeAndLatitude(wrapper, reqVO.getLongitude(), reqVO.getLatitude());
        return wrapper;
    }

    default void wrapKeyword(QueryWrapper<DO> wrapper, String keyword) {
        if (StrUtil.isNotEmpty(keyword)) {
            wrapper.like("detail_address", keyword);
        }
    }

    default void wrapRegionCode(QueryWrapper<DO> wrapper, String provinceCode, String cityCode, String countyCode) {
        if (StrUtil.isNotEmpty(provinceCode)) {
            wrapper.eq("province_code", provinceCode);
        }
        if (StrUtil.isNotEmpty(cityCode)) {
            wrapper.eq("city_code", cityCode);
        }
        if (StrUtil.isNotEmpty(countyCode)) {
            wrapper.eq("county_code", countyCode);
        }
    }

    default void wrapLongitudeAndLatitude(QueryWrapper<DO> wrapper, Double longitude, Double latitude) {
        if (latitude != null && longitude != null) {
            String sqlSegment = "(6378.138 * 2 * ASIN(SQRT(POW(SIN((latitude * PI() / 180 - {1} * PI() / 180) / 2),2) + COS(latitude * PI() / 180) * COS({1} * PI() / 180) * POW(SIN((longitude * PI() / 180 - {0} * PI() / 180) / 2),2))) * 1000) AS distance";
            wrapper.apply(sqlSegment, longitude, latitude);
            wrapper.orderByAsc("distance");
        }
    }

}
